<?php

	namespace nz\co\gravitate\FTAWebServices;
	
	
	define ("FTA_SOAP_DATETIME_FORMAT","Y-m-d\TH:i:s");

	class FTASOAPObject {
		
		var $name;
		var $params;
		var $ns;
	
		function __construct($name,$params, $ns=null){
			$this->name = $name;
			$this->params = $params;//an array of arguments..
			$this->ns = $ns;
		}
	
		function toXML(){
			return '<' . $this->name . (is_null($this->ns) ? '' : ' xmlns="' . $this->ns . '" ') . '>' . array_reduce($this->params, function ($v, FTASOAPArgument $w){ return $v . $w->toXML();}) . '</' . $this->name . '>';	
		}

	}

	class FTASOAPInvocation extends FTASOAPObject {	}
	
	class FTASOAPArgument {

		var $value;
		var $type;
		var $name;

		function __construct($type,$value,$name){

			$this->type = $type;
			$this->value = $value;
			$this->name = $name;

		}
			
		function toXML(){
			settype($this->value, $this->type);
			return '<' . $this->name . '>' . $this->value . '</' . $this->name . '>';
		}	
	}

	class FTASOAPEnvelope {
	
		var $header;
		var $body;
		var $ns;
		var $namespaces;
	
		function __construct(FTASOAPHeader $header, FTASOAPBody $body, $ns='soap', $namespaces=array()){
			$this->header = $header;
			$this->body = $body;
			$this->ns = $ns;
			$this->namespaces = $namespaces;
		}
	
		function toXML() {
			$el = ( is_null($this->ns) ? '' : $this->ns .':' ) . 'Envelope';		
			$namespaces = "";
			foreach($this->namespaces as $k => $v){
				$namespaces .= ' xmlns:' . $k .  '="' . $v . '"';
			}
			return 	'<?xml version="1.0" encoding="utf-8"?>' . "\n" . '<' . $el . $namespaces . ' >' . (is_null($this->header) ? "" : $this->header->toXML()) . (is_null($this->body) ? "" : $this->body->toXML()) . '</' . $el .  '>' ;
		}
	}

	class FTASOAPHeader {
	
		function __construct($header=null, $ns='soap'){
			$this->ns = $ns;
			$this->header = $header;
		}
	
		function toXML(){
			$el = ( is_null($this->ns) ? '' : $this->ns .':' ) . 'Header';
			return '<' . $el .'>' . (is_null($this->header) ? "" : $this->header->toXML()) . '</' . $el . '>';		
		}
	}

	class FTASOAPBody {
	
		var $invocation;
		var $ns;
	
		function __construct(FTASOAPInvocation $invocation,$ns=null){
			$this->invocation = $invocation;
			$this->ns = $ns;
		}
	
		function toXML(){
			$el = ( is_null($this->ns) ? '' : $this->ns .':' ) . 'Body';
			return '<' . $el .'>' . $this->invocation->toXML() . '</' . $el . '>';
		}
	}


	class FTASoapException extends \FTAException {
		
		var $payload;
		var $dict;
		
		function __construct($message, $payload,$dict){
			parent::__construct($message);
			$this->payload = $payload;
			$this->dict = $dict;	
		}
	}
	
	class NoServerResponseException extends FTASoapException {}
	
	class InvalidServerResponse extends FTASOAPArgument {};
	
	class SoapFaultException  extends FTASoapException{

		var $detail;
		var $code;
		var $faults; 
		
		function __construct($message, $payload,$faults, $dict){
			parent::__construct($message, $payload,$dict);
			$this->faults = $faults;
						
		}
	}

	class FTASoapFault {
		var $code;
		var $message;
		var $detail;		
	}

	
	

	abstract class FTASoapClient extends FTACurlPost {

		//raw xml result
		var $lastResponse;
		var $lastRawResponse;
		
		public function __construct($host, $port=80, $endPoint, $proxy=null, $proxyPort = '8888') {
			parent::__construct ($host, $port, $endPoint, $proxy, $proxyPort);
		}

		
		 public function __sleep() {
		 	$r = array(
				"host",
				"port",
				"endPoint",
				"httpVersion",
				"compress",
				"keepAlive",
				"verifyCertificates",
				"debug",
				"proxy",
				"proxyPort"
		 	);
		 	return $r;
		 }

		function getArgumentList($params){
			$arguments = array();
			if ( 1 <= count($params)){
			
			//	for($i = 1, $c = count($params); $i < $c; $i++){
				foreach ($params as $k=> $v){
				
				//	$v = $argv[ $i ];

					if ( is_float($v) || is_double($v)) {
					        $vType = "float";
					} else if (is_integer($v)){
					        $vType = "int";
					} else if (is_bool($v)){
					        $vType="bool";
					} else if (is_null($v)) {
					        $vType = "null";//like wtf!!
					} else if (is_object($v)) {
							$vType= "object";
					} else if (is_array($v)) {
							$vType = "array";
					} else {
					        $vType = "string";
					}
				
					array_push($arguments,
						new FTASOAPArgument($vType,$v, $k)
					);
				
				}
			}
			return $arguments;
		}		
		
		function getHeaderForMethod(){
			return new FTASOAPHeader();
		}	

		function getInvocationForMethodAndArguments($methodName, $arguments){
			return new FTASOAPInvocation( 
				$methodName,//
				$arguments,
				null
			);
		}
		
		// this is a simple wrapper that calls all of the various 
		// sub processes 
		function invokeMethod($method, $args){//arguments are magically taken.. 
		
			$payload = $this->payloadForInvocationWithNameAndArguments($method, $args);
			
	//		// attempt to deliver it
			$results =  $this->deliverPayload($payload->toXML(),'text/xml');
	
			if(is_null($results) || 0 == strlen($results)){
				throw new NoServerResponseException("The server returned no response for the invocation",$payload,array());
			}
			$this->lastRawResponse = $results;
			
			// add hooks here for the response string.. 
			$r = $this->processResponseStringForInvocation($payload->body->invocation, $results);
			
			return $r;
			
		}	

		abstract function processResponseStringForInvocation(FTASOAPInvocation $invocation, $string);
		
		abstract function payloadForInvocationWithNameAndArguments($methodName, $params);
				
		
		
	}
